/* omega copyright (c) 1987,1988,1989 by Laurence Raphael Brothers */
/* mspec.c */
/* monster special functions */

#include "glob.h"


void m_sp_mp(m)
struct monster *m;
{
  if (m->attacked && (random_range(3) == 1)) {
    mprint("You feel cursed!");
    p_damage(10,UNSTOPPABLE,"a mendicant priest's curse");
    m_vanish(m);
  }
  else if (! m_statusp(m,NEEDY)) {
    mprint("The mendicant priest makes a mystical gesture....");
    mprint("You feel impressed...");
    Player.alignment += 5;
    if (Player.alignment > 20)
      Player.hp = max(Player.hp,Player.maxhp);
    m_vanish(m);
  }
}



void m_sp_ng(m)
struct monster *m;
{
  if (distance(m->x,m->y,Player.x,Player.y) < 2)
    if ((random_range(5) == 1) || (Player.status[VULNERABLE]>0)) {
      mprint("The night gaunt grabs you and carries you off!");
      mprint("Its leathery wings flap and flap, and it giggles insanely.");
      mprint("It tickles you cunningly to render you incapable of escape.");
      mprint("Finally, it deposits you in a strange place.");
      p_teleport(0);
    }
}





void m_sp_poison_cloud(m)
struct monster *m;
{
  if (distance(m->x,m->y,Player.x,Player.y) < 3) {
    mprint("A cloud of poison gas surrounds you!");
    if (Player.status[BREATHING] > 0)
      mprint("You can breathe freely, however.");
    else p_poison(7);
  }
}


void m_sp_explode(m)
struct monster *m;
{
  if ((distance(Player.x,Player.y,m->x,m->y)<2) &&
      (m-> hp > 0) && 
      (m->hp < Monsters[m->id].hp))
    fball(m->x,m->y,m->x,m->y,m->hp);
}



void m_sp_demon(m)
struct monster *m;
{
  int mid;

  if (random_range(2)) {
    if ((m->id != ML4+6) && /*succubi don't give fear */
	los_p(m->x,m->y,Player.x,Player.y) &&
	(random_range(30) > Player.level+10) &&
	(Player.status[AFRAID] == 0)) {
      mprint("You are stricken with fear!");
      if (! p_immune(FEAR)) Player.status[AFRAID] += m->level;
      else mprint("You master your reptile brain and stand fast.");
    }
    else m_sp_spell(m);
  }
  if ((m->hp < (m->level * 5)) && (m->hp > 1)) {
    mprint("The demon uses its waning lifeforce to summon help!");
    m->hp = 1;
    switch(m->level) {
    case 3: mid = ML2+1; break; /* night gaunt */
    case 4:
    case 5: mid = ML3+2; break; /* lesser frost demon */
    case 6: mid = ML5+4; break; /* frost demon */
    case 7: mid = ML5+12; break; /* outer circle demon */
    case 8: mid = ML6+10; break; /* demon serpent */
    case 9: mid = ML7+14; break; /* inner circle demon */
    }
    summon(-1,mid);
    summon(-1,mid);
  }
}


void m_sp_acid_cloud(m)
struct monster *m;
{
  if (m_statusp(m,HOSTILE) &&
      (distance(m->x,m->y,Player.x,Player.y) < 3))
    acid_cloud();
}

	  
void m_sp_escape(m)
struct monster *m;
{
  if (m_statusp(m,HOSTILE))
    m_vanish(m);
}


void m_sp_ghost(m)
struct monster *m;
{
  if (m_statusp(m,HOSTILE)) {
    mprint("The ghost moans horribly....");
    p_damage(1,FEAR,"a ghost-inspired heart attack");
    mprint("You've been terrorized!");
    if (! p_immune(FEAR)) Player.status[AFRAID] += m->level;
    else mprint("You master your reptile brain and stand fast.");
  }
}




/* random spell cast by monster */
void m_sp_spell(m)
struct monster *m;
{
  char action[80];
  if (m_statusp(m,HOSTILE) && los_p(Player.x,Player.y,m->x,m->y)) {
    if (m->uniqueness == COMMON) strcpy(action,"The ");
    else strcpy(action,"");
    strcat(action,m->monstring);
    strcat(action," casts a spell...");
    mprint(action);
    if (! magic_resist(m->level)) switch (random_range(m->level+7)) {
    case 0: 
      nbolt(m->x,m->y,Player.x,Player.y,m->hit,10);
      break;
    case 1:
      mprint("It seems stronger..."); 
      m->hp += random_range(m->level*m->level);
      break;
    case 2:
      haste(-1);
      break;
    case 3:
      cure(-1);
      break;
    case 4:
      lball(m->x,m->y,Player.x,Player.y,20);
      break;
    case 5:
      enchant(-1);
    case 6:
      snowball(m->x,m->y,Player.x,Player.y,30);
      break;
    case 7:
      bless(0-m->level);
      break;
    case 8:
      p_poison(m->level);
      break;
    case 9:
      sleep_player(m->level/2);
      break;
    case 10:
      fbolt(m->x,m->y,Player.x,Player.y,m->hit*3,50);
      break;
    case 11:
      acquire(0-m->level);
      break;
    case 12:
      dispel(-1);
      break;
    case 13:
      disrupt(Player.x,Player.y,50);
      break;
    case 14:
      if (m->uniqueness == COMMON) {
	strcpy(Str2,"a ");
	strcat(Str2,m->monstring);
      }
      else strcpy(Str2,m->monstring);
      level_drain(m->level,Str2);
      break;
    case 15:
    case 16:
      disintegrate(Player.x,Player.y);
      break;
    }
  }
}



/* monsters with this have some way to hide, camouflage, etc until they 
   attack */
void m_sp_surprise(m)
struct monster *m;
{
  if (m->attacked) {
    if (m_statusp(m,HOSTILE) && 
	(! Player.status[TRUESIGHT]) &&
	m_statusp(m,M_INVISIBLE)) {
      m->monchar = Monsters[m->id].monchar;
      if (! Player.status[ALERT]) {
	switch(random_range(4)) {
	case 0: 
	  mprint("You are surprised by a sudden treacherous attack!");
	  break;
	case 1: 
	  mprint("You are shocked out of your reverie by the scream of battle!");
	  break;
	case 2: 
	  mprint("Suddenly, from out of the shadows, a surprise attack!");
	  break;
	case 3: 
	  mprint("A shriek of hatred causes you to momentarily freeze up!");
	  break;
	}
	morewait();
	setgamestatus(SKIP_PLAYER);
	m_status_reset(m,M_INVISIBLE);
      }
      else {
	mprint("You alertly sense the presence of an attacker!");
	m_status_reset(m,M_INVISIBLE);
      }	
    }
  }
}

void m_sp_whistleblower(m)
struct monster *m;
{
  if (m_statusp(m,HOSTILE)) {
    alert_guards();
    m->specialf = M_MELEE_NORMAL;
  }
}


void m_sp_seductor(m)
struct monster *m;
{
  if (m_statusp(m,HOSTILE)) {
    if (m->uniqueness == COMMON) {
      strcpy(Str2,"The ");
      strcat(Str2,m->monstring);
    }
    else strcpy(Str2,m->monstring);
    strcat(Str2," runs away screaming for help....");
    mprint(Str2);
    m_vanish(m);
    summon(-1,-1);
    summon(-1,-1);
    summon(-1,-1);
  }
  else if (distance(Player.x,Player.y,m->x,m->y) < 2) 
    m_talk_seductor(m);

}


void m_sp_demonlover(m)
struct monster *m;
{
  if (distance(Player.x,Player.y,m->x,m->y) < 2) 
    m_talk_demonlover(m);
}

void m_sp_eater(m)
struct monster *m;
{
  int i;
  if (Player.rank[COLLEGE]) m_status_set(m,HOSTILE);
  if (m_statusp(m,HOSTILE))
    if (los_p(m->x,m->y,Player.x,Player.y)) {
      mprint("A strange numbing sensation comes over you...");
      morewait();
      Player.mana = Player.mana / 2;
      if (random_range(4)) enchant(-1);
      else dispel(-1);
      Player.pow--;
      if (--Player.pow < 1) p_death("the Eater of Magic");
    }
  if (m->hp < 10) {
    mprint("The Eater explodes in a burst of mana!");
    manastorm(m->x,m->y,1000);
  }
}


void m_sp_dragonlord(m)
struct monster *m;
{
  if (m_statusp(m,HOSTILE)) {
    if (distance(m->x,m->y,Player.x,Player.y)<2) {
      if (! Player.status[IMMOBILE]) {
	mprint("A gust of wind from the Dragonlord's wings knocks you down!");
	p_damage(25,NORMAL_DAMAGE,"a gust of wind");
	setgamestatus(SKIP_PLAYER);
	Player.status[IMMOBILE]+=2;
      }
      else if (! Constriction) {
	mprint("The Dragonlord grabs you with his tail!");
	Constriction = 25;
	Player.status[IMMOBILE]+=1;
      }
      else if (random_range(2)) {
	mprint("The coils squeeze tighter and tighter...");
	p_damage(Constriction,NORMAL_DAMAGE,"the Dragonlord");
	Player.status[IMMOBILE]+=1;
	Constriction *=2;
      }
      else {
	mprint("The dragonlord hurls you to the ground!");
	p_damage(2*Constriction,NORMAL_DAMAGE,"the Dragonlord");
	Constriction = 0;
      }
      m_sp_spell(m);
    }
    else {
      Constriction = 0;
      if (view_los_p(m->x,m->y,Player.x,Player.y)) {
	if ((! Player.immunity[FEAR]) && (! Player.status[AFRAID])) {
	  mprint("You are awestruck at the sight of the Dragonlord.");
	  Player.status[AFRAID]+=5;
	}
	if (random_range(3)) {
	  m_sp_spell(m);
	  m_sp_spell(m);
	}
      }
    }
  }
  else if (distance(m->x,m->y,Player.x,Player.y)<2)
    mprint("You are extremely impressed at the sight of the Dragonlord.");
}


void m_sp_blackout(m)
struct monster *m;
{
  if ((distance(m->x,m->y,Player.x,Player.y) < 4) &&
      (Player.status[BLINDED] == 0)) {
    mprint("The fungus emits a burst of black spores. You've been blinded!");
    if (Player.status[TRUESIGHT] > 0) mprint("The blindness quickly passes.");
    else Player.status[BLINDED]+=4;
  }
  if (loc_statusp(m->x,m->y,LIT)) {
    mprint("The fungus chirps.... ");
    mprint("The area is plunged into darkness.");
    torch_check();torch_check();torch_check();
    torch_check();torch_check();torch_check();
    spreadroomdark(m->x,m->y,Level->site[m->x][m->y].roomnumber);
    levelrefresh();
  }
}


void m_sp_bogthing(m)
struct monster *m;
{
  if (Player.status[IMMOBILE] && 
      (distance(Player.x,Player.y,m->x,m->y) < 2)) {
    if (! Player.status[AFRAID]) {
      mprint("As the bogthing touches you, you feel a frisson of terror....");
      if (Player.immunity[FEAR]) mprint("which you shake off.");
      else Player.status[AFRAID]+=2;
    }
    else {
      mprint("The bogthing's touch causes you scream in agony!");
      p_damage(50,UNSTOPPABLE,"fright");
      mprint("Your struggles grow steadily weaker....");
      Player.con--;
      Player.str--;
      if ((Player.con < 3) || (Player.str < 3))
	p_death("congestive heart failure");
    }
  }
}


void m_sp_were(m)
struct monster *m;
{
  int mid;
  if (m_statusp(m,HOSTILE) || (Phase == 6)) {
    do mid = random_range(ML9-NML_0)+ML1;
    while ((Monsters[mid].uniqueness != COMMON) ||
	   (! m_statusp(&(Monsters[mid]),MOBILE)) ||
	   (! m_statusp(&(Monsters[mid]),HOSTILE)));
    m->id = Monsters[mid].id;
    m->hp += Monsters[mid].hp;
    m->status |= Monsters[mid].status;
    m->ac = Monsters[mid].ac;
    m->dmg = Monsters[mid].dmg;
    m->speed = Monsters[mid].speed;
    m->immunity |= Monsters[mid].immunity;
    m->xpv += Monsters[mid].xpv;
    m->corpseweight = Monsters[mid].corpseweight;
    m->monchar = Monsters[mid].monchar;
    m->talkf = Monsters[mid].talkf;
    m->meleef = Monsters[mid].meleef;
    m->strikef = Monsters[mid].strikef;
    m->specialf = Monsters[mid].specialf;
    strcpy(Str1,"were-");
    strcat(Str1,Monsters[mid].monstring);
    strcpy(Str2,"dead were-");
    strcat(Str2,Monsters[mid].monstring);
    m->monstring = salloc(Str1);
    m->corpsestr = salloc(Str2);
    m->immunity += pow2(NORMAL_DAMAGE);
    if (los_p(m->x,m->y,Player.x,Player.y)) 
      mprint("You witness a hideous transformation!");
    else mprint("You hear a distant howl.");
  }
}    


void m_sp_servant(m)
struct monster *m;
{
  if ((m->id == ML4+12) && (Player.alignment < 0))
    m_status_set(m,HOSTILE);
  else if ((m->id == ML4+13) && (Player.alignment > 0))
    m_status_set(m,HOSTILE);
}


void m_sp_av(m)
struct monster *m;
{
  if (Player.mana > 0) {
    mprint("You feel a sudden loss of mana!");
    Player.mana -= (max(0,10-distance(m->x,m->y,Player.x,Player.y)));
    dataprint();
  }
}

void m_sp_lw(m)
struct monster *m;
{
  if (random_range(2)) {
    if (Level->site[m->x][m->y].locchar == FLOOR) {
      Level->site[m->x][m->y].locchar = LAVA;
      Level->site[m->x][m->y].p_locf = L_LAVA;
      lset(m->x, m->y, CHANGED);
    }
    else if (Level->site[m->x][m->y].locchar == WATER) {
      Level->site[m->x][m->y].locchar = FLOOR;
      Level->site[m->x][m->y].p_locf = L_NO_OP;
      lset(m->x, m->y, CHANGED);
    }
  }
}


void m_sp_angel(m)
struct monster *m;
{
  int mid,hostile = FALSE;
  switch(m->aux1) {
  case ATHENA:
  case ODIN: 
    hostile = ((Player.patron == HECATE) || (Player.patron == SET));
    break;
  case SET:
  case HECATE: 
    hostile = ((Player.patron == ODIN) || (Player.patron == ATHENA));
    break;
  case DESTINY:
    hostile = (Player.patron != DESTINY);
    break;
  }
  if (hostile)
    m_status_set(m,HOSTILE);
  if (m_statusp(m,HOSTILE)) {
    mprint("The angel summons a heavenly host!");
    switch(m->level) {
    case 9: mid = ML8+11; break; /* high angel */
    case 8: mid = ML6+11; break; /* angel */
    default:
    case 6: mid = ML3+4; break; /* phantom */
    }
    summon(-1,mid);
    summon(-1,mid);
    summon(-1,mid);
    /* prevent angel from summoning infinitely */
    m->specialf = M_NO_OP;
  }
}


/* Could completely fill up level */
void m_sp_swarm(m)
struct monster *m;
{
  if (random_range(5)==1) {
    if (view_los_p(m->x,m->y,Player.x,Player.y))
      mprint("The swarm expands!");
    else mprint("You hear an aggravating humming noise.");
    summon(-1,ML4+14);
  }
}




/* raise nearby corpses from the dead.... */
void m_sp_raise(m)
struct monster *m;
{
  int x,y;
  pol t;
  for(x=m->x-2;x<=m->x+2;x++)
    for(y=m->y-2;y<=m->y+2;y++)
      if (inbounds(x,y)) 
	if (Level->site[x][y].things != NULL)
	  if (Level->site[x][y].things->thing->id == CORPSEID) {
	    mprint("The Zombie Overlord makes a mystical gesture...");
	    summon(-1,Level->site[x][y].things->thing->charge);
	    t = Level->site[x][y].things;
	    Level->site[x][y].things = Level->site[x][y].things->next;
	    free((char *) t);
	  }
}




void m_sp_mb(m)
struct monster *m;
{
  if (distance(m->x,m->y,Player.x,Player.y)==1) {
    mprint("The manaburst explodes!");
    if (m_statusp(m,HOSTILE)) {
      mprint("You get blasted!");
      p_damage(random_range(100),UNSTOPPABLE,"a manaburst");
      mprint("You feel cold all over!");
      Player.pow-=3;
      Player.iq--;
      Player.con--;
      Player.str-=2;
      Player.dex--;
      Player.agi--;
      dispel(-1);
    }
    else {
      mprint("You feel toasty warm inside!");
      Player.pow++;
      Player.mana = max(Player.mana,calcmana());
      Player.hp = max(Player.hp,++Player.maxhp);
    }
    m->hp = 0;
  }
}


void m_sp_mirror(m)
struct monster *m;
{
  int i,x,y;
  if (view_los_p(m->x,m->y,Player.x,Player.y)) {
    if (random_range(20)+6 < m->level) {
      summon(-1,m->id);
      mprint("You hear the sound of a mirror shattering!");
    }
    else for(i=0;i<5;i++) {
      x = m->x + random_range(13)-6;
      y = m->y + random_range(13)-6;
      if (inbounds(x,y)) {
	Level->site[x][y].showchar = m->monchar;
	putspot(x,y,m->monchar);
      }
    }
  }
}



void m_illusion(m)
struct monster *m;
{
  int i = random_range(NUMMONSTERS);
  if (i==NPC || i==HISCORE_NPC) i = m->id; /* can't imitate NPC */
  if (Player.status[TRUESIGHT]) {
    m->monchar = Monsters[m->id].monchar;
    m->monstring = Monsters[m->id].monstring;
  }
  else  if (random_range(5) == 1) {
    m->monchar = Monsters[i].monchar;
    m->monstring = Monsters[i].monstring;
  }
}




void m_huge_sounds(m)
struct monster *m;
{
  if (m_statusp(m,AWAKE) &&
      (! los_p(m->x,m->y,Player.x,Player.y)) &&
      (random_range(10) == 1))
    mprint("The dungeon shakes!");
}



void m_thief_f(m)
struct monster *m;
{
  int i = random_item();
  if (random_range(3) == 1) {
    if (distance(Player.x,Player.y,m->x,m->y) < 2) {
      if (p_immune(THEFT) || (Player.level > (m->level*2)+random_range(20))) 
	mprint("You feel secure.");
      else {
	if (i == ABORT)
	  mprint("You feel fortunate.");
	else if ((Player.possessions[i]->used) || 
		 (Player.dex < m->level*random_range(10))) {
	  mprint("You feel a sharp tug.... You hold on!");
	}
	else {
	  mprint("You feel uneasy for a moment.");
	  if (m->uniqueness == COMMON) {
	    strcpy(Str2,"The ");
	    strcat(Str2,m->monstring);
	  }
	  else strcpy(Str2,m->monstring);
	  strcat(Str2," suddenly runs away for some reason.");
	  mprint(Str2);
	  m_teleport(m);
	  m->movef = M_MOVE_SCAREDY;
	  m->specialf = M_MOVE_SCAREDY;
	  m_pickup(m,Player.possessions[i]);
	  conform_unused_object(Player.possessions[i]);
	  Player.possessions[i] = NULL;
	}
      }
    }
  }
}


void m_summon(m)
struct monster *m;
{
  if ((distance(Player.x,Player.y,m->x,m->y) < 2) &&
      (random_range(3) == 1)) {
	summon(0,-1);
	summon(0,-1);
      }
}	  


void m_aggravate(m)
struct monster *m;
{

  if (m_statusp(m,HOSTILE)) {
    if (m->uniqueness == COMMON) {
      strcpy(Str2,"The ");
      strcat(Str2,m->monstring);
    }
    else strcpy(Str2,m->monstring);
    strcat(Str2," emits an irritating humming sound.");
    mprint(Str2);
    aggravate();
    m_status_reset(m,HOSTILE);
  }
}



void m_sp_merchant(m)
struct monster *m;
{
  pml ml;
  if (m_statusp(m,HOSTILE))
    if (Current_Environment == E_VILLAGE) {
      mprint("The merchant screams: 'Help! Murder! Guards! Help!'");
      mprint("You hear the sound of police whistles and running feet.");
      for (ml=Level->mlist;ml!=NULL;ml=ml->next) {
	m_status_set(ml->m,AWAKE);
	m_status_set(ml->m,HOSTILE);
      }
      m->specialf = M_NO_OP;
    }
}

/* The special function of the various people in the court of the archmage */
/* and the sorcerors' circle */
void m_sp_court(m)
struct monster *m;
{
  pml ml;
  if (m_statusp(m,HOSTILE)) {
    mprint("A storm of spells hits you!");
    for(ml=Level->mlist;ml!=NULL;ml=ml->next) {
      m_status_set(ml->m,HOSTILE);
      m_sp_spell(ml->m);
      if (ml->m->specialf == M_SP_COURT)
	ml->m->specialf = M_SP_SPELL;
    }
  }
}


/* The special function of the dragons in the dragons' lair */
void m_sp_lair(m)
struct monster *m;
{
  pml ml;
  if (m_statusp(m,HOSTILE)) {
    mprint("You notice a number of dragons waking up....");
    mprint("You are struck by a quantity of firebolts.");
    morewait();
    for(ml=Level->mlist;ml!=NULL;ml=ml->next)
      if (ml->m->hp > 0 && ml->m->specialf == M_SP_LAIR) {
	m_status_set(ml->m,HOSTILE);
	fbolt(ml->m->x,ml->m->y,Player.x,Player.y,100,100);
	if (ml->m->id == ML10+3)
	  ml->m->specialf = M_SP_DRAGONLORD;
	else
	  ml->m->specialf = M_STRIKE_FBOLT;
      }
  }
}


void m_sp_prime(m)
struct monster *m;
{
  if (m_statusp(m,HOSTILE)) {
    mprint("The prime sorceror gestures and a pentacular gate opens!");
    mprint("You are surrounded by demons!");
    summon(-1,ML9+7);
    summon(-1,ML9+7);
    summon(-1,ML9+7);
    summon(-1,ML9+7);
  }
  m->specialf = M_SP_SPELL;
}
